﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Telerik.WinControls.UI;
using MySQLStudio.BusinessLogic;
using MySQLStudio.Common;
using MySQLStudio.Common.Data;

namespace MySQLStudio.GUI.Controls.Table
{
    public partial class TableControl : UserControl
    {
        private Host m_host;
        private Database m_database;
        private MySQLStudio.BusinessLogic.Table m_table;
        private Point m_downPoint;
        private bool m_isDragging;       
        private Rectangle m_dragBoxFromMouseDown;
        private GridViewDataRowInfo m_newRow;
        private Column m_newColumn;
        RadDropDownMenu columnContextMenu;
        RadMenuItem insertColumnContextMenuItem;
        RadMenuItem deleteColumnContextMenuItem;
        private EventHandler<TableSavedEventArgs> m_TableSaved;

        public event EventHandler<TableSavedEventArgs> TableSaved
        {
            add
            {
                this.m_TableSaved += value;
            }
            remove
            {
                this.m_TableSaved -= value;
            }
        }

        private void OnTableSaved()
        {
            if (this.m_TableSaved != null)
            {
                this.m_TableSaved(this, new TableSavedEventArgs(this.Host.Hostname, this.Database.Name, this.Table.Name));
            }
        }

        public Database Database
        {
            get
            {
                return m_database;
            }
            set
            {
                m_database = value;
            }
        }

        public Host Host
        {
            get
            {
                return m_host;
            }
            set
            {
                m_host = value;
            }
        }

        public MySQLStudio.BusinessLogic.Table Table
        {
            get
            {
                return m_table;
            }
            set
            {
                m_table = value;
            }
        }       

        public TableControl()
        {
            InitializeComponent();           
        }

        private void TableControl_Load(object sender, EventArgs args)        
        {
            GridViewComboBoxColumn cmbDataTypesColumn = (GridViewComboBoxColumn)this.tableDesignGridView.Columns[1];

            cmbDataTypesColumn.DataSource = DataUtils.DataTypes.DataTypes;
            cmbDataTypesColumn.DropDownStyle = Telerik.WinControls.RadDropDownStyle.DropDown;            

            if (this.Table == null)
            {
                this.Table = MySQLStudio.BusinessLogic.Table.CreateEmptyTable(this.Host, this.Database);

                this.Table.Columns.Add(new Column());                
            }

            this.tableDesignGridView.DataSource = this.Table.Columns;
            this.columnPropertyGrid.SelectedObject = this.Table.Columns[0];

            this.columnContextMenu = new RadDropDownMenu();
            this.insertColumnContextMenuItem = new RadMenuItem("Insert Column");
            this.deleteColumnContextMenuItem = new RadMenuItem("Delete Column");

            this.insertColumnContextMenuItem.Click += new EventHandler(insertColumnContextMenuItem_Click);
            this.deleteColumnContextMenuItem.Click += new EventHandler(deleteColumnContextMenuItem_Click);
        }        

        private void tableDesignGridView_RowsChanged(object sender, GridViewCollectionChangedEventArgs e)
        {
            if (e.Action == Telerik.WinControls.Data.NotifyCollectionChangedAction.Add)
            {
                this.m_newRow = (GridViewDataRowInfo)e.NewItems[0];                
                                
                this.tableDesignGridView.Invalidate();                

                if (this.tableDesignGridView.CurrentRow != this.m_newRow)
                {
                    this.tableDesignGridView.CurrentRow = this.m_newRow;                    
                }
            }
        }            

        private void tableDesignGridView_CurrentRowChanged(object sender, CurrentRowChangedEventArgs e)
        {
            if (e.OldRow is GridViewNewRowInfo)
            {
                if (this.m_newRow != null && this.tableDesignGridView.Rows.IndexOf(this.m_newRow) != -1)
                {
                    this.tableDesignGridView.CurrentRow = this.m_newRow;
                    this.m_newRow.EnsureVisible();

                    this.ConfigureRow(this.m_newRow);
                }

                this.m_newRow = null;
            }           

            this.columnPropertyGrid.SelectedObject = this.tableDesignGridView.CurrentRow.DataBoundItem;
        }

        private void tableDesignGridView_CellValueChanged(object sender, GridViewCellEventArgs e)
        {
            if (e.Column is GridViewDataColumn)
            {
                this.columnPropertyGrid.SelectedObject = e.Row.DataBoundItem;

                if (e.ColumnIndex == 1)
                {
                    this.ConfigureRow(e.Row);
                }
            }
        }

        private void ConfigureRow(GridViewRowInfo row)
        {
            Column column = (Column)row.DataBoundItem;

            if (row is GridViewNewRowInfo)
            {
                column = this.m_newColumn;
            }            

            if (column != null && column.DataType != null)
            {
                DbDataType dataType = DataUtils.DataTypes.FirstOrDefault(dt => dt.Name == column.DataType);

                row.Cells[2].CellElement.Enabled = dataType.EnableLength;
                row.Cells[3].CellElement.Enabled = dataType.EnablePrecision;
                row.Cells[4].CellElement.Enabled = dataType.EnableScale;

                if (dataType.EnableCollation)
                {
                    column.Collation = this.Table.Collation;
                }
                else
                {
                    column.Collation = null;
                }
            }

            if (row is GridViewNewRowInfo)
            {
                this.m_newColumn = null;
            }
        }

        private void tableDesignGridView_MouseDown(object sender, MouseEventArgs e)
        {
            this.m_downPoint = e.Location;

            Telerik.WinControls.RadElement element = this.tableDesignGridView.ElementTree.GetElementAtPoint(
                    this.m_downPoint);

            if ((element is GridDataCellElement || element is GridRowHeaderCellElement)
                && !(element is GridTableHeaderCellElement))
            {
                Size dragSize = SystemInformation.DragSize;

                this.m_dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
                    e.Y - (dragSize.Height / 2)), dragSize);
            }
            else
            {
                this.m_dragBoxFromMouseDown = Rectangle.Empty;
            }
        }       

        private void tableDesignGridView_DragDrop(object sender, DragEventArgs e)
        {
            int rowIndex = Convert.ToInt32(e.Data.GetData(typeof(int)));            

            Telerik.WinControls.RadElement element = this.tableDesignGridView.ElementTree.GetElementAtPoint(
                this.tableDesignGridView.PointToClient(new Point(e.X, e.Y)));

            GridCellElement cellElement = element as GridCellElement;

            Column columnToDrop = this.Table.Columns[rowIndex];            

            if (element is GridNewRowElement || (cellElement != null && cellElement.RowIndex == -1))
            {
                this.Table.Columns.Remove(columnToDrop);
                this.Table.Columns.Add(columnToDrop);                
            }

            if (element != null && cellElement.RowIndex != -1)
            {
                int targetRowIndex =(element as GridCellElement).RowIndex;

                this.Table.Columns.Remove(columnToDrop);                 
                this.Table.Columns.Insert(targetRowIndex, columnToDrop);
            }

            this.m_isDragging = false;
            this.tableDesignGridView.Cursor = Cursors.Arrow;
            this.tableDesignGridView.Capture = false;
            this.tableDesignGridView.Invalidate();
        }

        private void tableDesignGridView_DragOver(object sender, DragEventArgs e)
        {
            Telerik.WinControls.RadElement element = this.tableDesignGridView.ElementTree.GetElementAtPoint(
                this.tableDesignGridView.PointToClient(new Point(e.X, e.Y)));

            if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move
                && (element is GridDataCellElement || element is GridRowHeaderCellElement || element is GridNewRowElement)
                && !(element is GridTableHeaderCellElement))
            {
                e.Effect = DragDropEffects.Move;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void tableDesignGridView_MouseMove(object sender, MouseEventArgs e)
        {            
            if (e.Button == MouseButtons.Left && !this.m_isDragging && this.IsRealDragging(e.Location)                )
            {
                Telerik.WinControls.RadElement element = this.tableDesignGridView.ElementTree.GetElementAtPoint(
                    this.m_downPoint);

                if (element is GridDataCellElement || element is GridRowHeaderCellElement)
                {
                    this.m_isDragging = true;

                    this.tableDesignGridView.Cursor = Cursors.Hand;
                    this.tableDesignGridView.Capture = true;

                    int rowIndex = this.tableDesignGridView.CurrentRow.GridViewInfo.CurrentIndex;

                    DragDropEffects effects = this.tableDesignGridView.DoDragDrop(rowIndex, DragDropEffects.All);
                }
            }

            if (e.Button != MouseButtons.Left)
            {
                this.m_isDragging = false;
                this.tableDesignGridView.Cursor = Cursors.Arrow;
                this.tableDesignGridView.Capture = false;                
            }
        }

        private bool IsRealDragging(Point mousePosition)
        {
            return this.m_dragBoxFromMouseDown != Rectangle.Empty
                && !this.m_dragBoxFromMouseDown.Contains(mousePosition);
        }

        private void tableDesignGridView_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            if (e.EscapePressed || !this.m_isDragging)
            {
                e.Action = DragAction.Cancel;
            }            
        }

        private void tableDesignGridView_GiveFeedback(object sender, GiveFeedbackEventArgs e)
        {
            e.UseDefaultCursors = true;
        }

        public void Save()
        {
            try
            {
                if (this.Table.IsPersisted)
                {
                    this.Table.Alter(this.Host, this.Database);
                }
                else
                {
                    ChooseTableName chooseTableName = new ChooseTableName();

                    if (chooseTableName.ShowDialog() == DialogResult.OK)
                    {
                        this.Table.Name = chooseTableName.TableName;
                        this.Table.Create(this.Host, this.Database);
                    }
                }

                this.OnTableSaved();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error saving the table", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void tableDesignGridView_ContextMenuOpening(object sender, ContextMenuOpeningEventArgs e)
        {
            GridRowHeaderCellElement cell = e.ContextMenuProvider as GridRowHeaderCellElement;

            if (cell != null && !(cell is GridTableHeaderCellElement))
            {
                e.ContextMenu.Items.Clear();
                e.ContextMenu.Items.Add(this.insertColumnContextMenuItem);
                e.ContextMenu.Items.Add(this.deleteColumnContextMenuItem);

                this.insertColumnContextMenuItem.Tag = cell.RowIndex;
                this.deleteColumnContextMenuItem.Tag = cell.RowIndex;

                e.Cancel = false;
            }
            else
            {
                e.Cancel = true;
            }
        }

        void deleteColumnContextMenuItem_Click(object sender, EventArgs e)
        {
            int rowIndex = (int)this.deleteColumnContextMenuItem.Tag;
            //this.tableDesignGridView.Rows.RemoveAt(rowIndex);

            if (rowIndex != -1)
            {
                this.Table.Columns.RemoveAt(rowIndex);
            }
        }

        void insertColumnContextMenuItem_Click(object sender, EventArgs e)
        {
            Column newColumn = new Column();

            int rowIndex = (int)this.insertColumnContextMenuItem.Tag;
            this.Table.Columns.Insert(rowIndex, newColumn);
        }

        private void tableDesignGridView_DataBindingComplete(object sender, GridViewBindingCompleteEventArgs e)
        {
            this.Table.Columns.ListChanged += new ListChangedEventHandler(Columns_ListChanged);

            foreach (GridViewDataRowInfo row in this.tableDesignGridView.Rows)
            {
                this.ConfigureRow(row);               
            }
        }

        void Columns_ListChanged(object sender, ListChangedEventArgs e)
        {
            if (e.ListChangedType == ListChangedType.ItemAdded)
            {
                this.m_newColumn = this.Table.Columns[e.NewIndex];

                this.ConfigureRow(this.tableDesignGridView.CurrentRow);
            }
        }                                               
    }
}
